package com.gmrz.uaf.remote.protocol.v1.processor;

import com.gmrz.service.challengestore.ChallengeStoreException;
import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.UAFBaseProcessor;
import com.gmrz.uaf.protocol.v1.processor.exception.AuthenticationFailedException;
import com.gmrz.uaf.protocol.v1.processor.exception.PolicyNotFoundException;
import com.gmrz.uaf.protocol.v1.processor.exception.PossibleReplayAttackException;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.*;
import com.gmrz.uaf.protocol.v1.validaton.ValidationException;
import com.gmrz.uaf.protocol.v1.validaton.Validator;
import com.gmrz.uaf.remote.plugin.AuthServicePluginManager;
import com.gmrz.uaf.remote.protocol.v1.validation.auth.UAPIDAuthResponseValidator;
import com.gmrz.uas.plugin.authservice.AuthServiceData;
import com.gmrz.uas.plugin.authservice.AuthServicePlugin;
import com.gmrz.uas.plugin.exception.PluginException;
import com.gmrz.util.Convert;
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by gongyuqiang on 2017/5/8.
 */
public class UAPIDAuthFinishProcessor extends UAFBaseProcessor{
    private static final Logger LOG = LogManager.getLogger(UAPIDAuthFinishProcessor.class);

    AuthServicePluginManager serviceManager;

    @Inject
    public void setServiceManager(AuthServicePluginManager serviceManager) {
        this.serviceManager = serviceManager;
    }

    /**
     * 实名认证
     * @param response
     * @param appID
     * @param authType
     * @param hashedUserName
     * @param transType
     * @throws PossibleReplayAttackException
     * @throws ChallengeStoreException
     * @throws PolicyNotFoundException
     * @throws DAOException
     * @throws ValidationException
     */
    public void process(AuthenticationResponse response, String appID, String authType, String hashedUserName,String transType) throws PossibleReplayAttackException, ChallengeStoreException, PolicyNotFoundException, DAOException, ValidationException {

        LOG.info("UAPIDAuthFinishProcessor Validating authentication response");


        Validator<AuthenticationResponse> authRespValidator = new UAPIDAuthResponseValidator(this.serverConfig,
                Constants.Operation.REG,appID,transType);
        authRespValidator.validate(response);

        ServerData serverData = response.getOperationHeader().getServerData();
        checkForReplayAttack(serverData);

        List<Extension> exts = response.getOperationHeader().getExtensions();
        processExtensions(exts);

        TLSData tlsData = response.getFinalChallengeParams().getTLSData();
        processTLSData(tlsData);

        String plainUserName = serverData.getUserName();

        String policyName = serverData.getPolicyName();
        LOG.info("Auth Response userAliasName[{}], policyname[{}]", plainUserName, policyName);

        AuthenticatorRegistration authentication = response.getAuthentication();
        if(authentication == null){
            String msg = "No AuthenticatorRegistration found in the registration response for user[" + plainUserName + "], policy["
                    + policyName + "].";

            logAndThrowAFE(msg);
        }

        String aaid = authentication.getAaid();
        Policy p = this.policyManager.getNamedPolicy(authType,appID,transType);
        LOG.info("Policy:" + UAFSchemaBuilder.getGson().toJson(p));
        if(p == null || !isAcceptedAaid(p, aaid)){
            LOG.error("Requested policy {} is not available on server", "POLICY_"+appID+"_"+authType);
            throw new PolicyNotFoundException(UAFErrorCode.BIZ_POLICY_NOT_FOUND);
        }

        List<AuthServiceData> contents = new ArrayList<AuthServiceData>();
        for(Extension ext: authentication.getExtensions()){
            AuthServiceData content = new AuthServiceData();
            content.setId(ext.getId());
            content.setContent(Convert.fromBase64(ext.getData()));
            contents.add(content);
        }


        try{
            AuthServicePlugin service = serviceManager.getServicePlugin(aaid,authType);
            service.authenticate(null, contents);
        }
        catch (PluginException e){
            LOG.error(e.getErrorMsg());
            throw new AuthenticationFailedException(e.getErrorMsg());
        }

    }
    protected void logAndThrowAFE(String msg) {
        LOG.error(msg);
        throw new AuthenticationFailedException(msg);
    }
}
